import sys
import time

import requests
from lxml import etree
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, \
     QTextEdit, QFileDialog, QWidget, QDialog, QPushButton, QApplication, QMainWindow, QDesktopWidget
from PyQt5.QtCore import pyqtSlot, Qt, QThread, pyqtSignal, QObject
from PyQt5.QtGui import QIcon
import urllib3
from PyQt5.QtGui import QTextCursor
from urllib.parse import urlparse
import openpyxl
from openpyxl.styles import Font, Alignment
import time

# 禁用InsecureRequestWarning
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

def fetch_seo_data(url):
    """获取并解析SEO数据"""
    url = "https://www.aizhan.com/cha/{}/".format(url.strip())
    headers = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
        'Accept-Language': 'en,zh-CN;q=0.9,zh;q=0.8,vi;q=0.7',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive',
        'Pragma': 'no-cache',
        'Referer': 'https://www.aizhan.com/',
        'Sec-Fetch-Dest': 'document',
        'Sec-Fetch-Mode': 'navigate',
        'Sec-Fetch-Site': 'same-origin',
        'Sec-Fetch-User': '?1',
        'Upgrade-Insecure-Requests': '1',
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1',
        'sec-ch-ua': '"Not?A_Brand";v="8", "Chromium";v="108", "Google Chrome";v="108"',
        'sec-ch-ua-mobile': '?0',
        'sec-ch-ua-platform': 'linux',
    }
    try:
        response = requests.get(url=url, headers=headers, timeout=10)
        time.sleep(0.5)
        response.raise_for_status()  # 检查请求是否成功
        lxml_tree = etree.HTML(response.text)
        return lxml_tree
    except requests.RequestException as e:
        print(f"请求错误: {e}")
        return None

def parse_and_print_results(tree, url):
    """解析并打印SEO报告"""
    if tree is None:
        print("无法获取数据，请检查网络或URL。")
        return

    href_name = tree.xpath('//div[@id="webpage_title"]//text()')
    print(f"\nURL: {url}\nTitle信息: {''.join(href_name)}")

    rank_info = {
        '百度权重': tree.xpath('//a[@id="baidurank_br"]//img/@alt'),
        '移动权重': tree.xpath('//a[@id="baidurank_mbr"]//img/@alt'),
        '360权重': tree.xpath('//a[@id="360_pr"]//img/@alt'),
        '神马权重': tree.xpath('//a[@id="sm_pr"]//img/@alt'),
        '搜狗权重': tree.xpath('//a[@id="sogou_pr"]//img/@alt'),
        '谷歌PR': tree.xpath('//a[@id="google_pr"]//img/@alt'),
    }

def query_from_file(filepath):
    """从文件中读取并查询多个网址"""
    with open(filepath, "r", encoding="utf-8") as file:
        for url in file:
            url = url.strip()
            tree = fetch_seo_data(url)
            if tree is not None:
                parse_and_print_results(tree, url)

class BatchQueryWorker(QObject):
    """处理批量查询任务的工作者线程"""
    finished = pyqtSignal()
    error = pyqtSignal(tuple)
    result = pyqtSignal(dict)  # 使用字典类型来传递查询结果

    def __init__(self, urls):
        super().__init__()
        self.urls = urls

    def query_aizhan(self, url):
        """查询单个URL在aizhan.com上的SEO信息"""
        try:
            headers = {
                'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
                'Accept-Language': 'en,zh-CN;q=0.9,zh;q=0.8,vi;q=0.7',
                'Cache-Control': 'no-cache',
                'Connection': 'keep-alive',
                'Pragma': 'no-cache',
                'Referer': 'https://www.aizhan.com/',
                'Sec-Fetch-Dest': 'document',
                'Sec-Fetch-Mode': 'navigate',
                'Sec-Fetch-Site': 'same-origin',
                'Sec-Fetch-User': '?1',
                'Upgrade-Insecure-Requests': '1',
                'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1',
                'sec-ch-ua': '"Not?A_Brand";v="8", "Chromium";v="108", "Google Chrome";v="108"',
                'sec-ch-ua-mobile': '?0',
                'sec-ch-ua-platform': 'linux',
            }
            response = requests.get(f"https://www.aizhan.com/cha/{url}/", headers=headers, verify=False)
            if response.status_code == 200:
                result_dict = {
                    'url': url,
                    'title': "",
                    'weights': {},
                    'icp': ""
                }
                tree = etree.HTML(response.text)

                # 提取标题
                title_elements = tree.xpath('//div[@id="webpage_title"]//text()')
                result_dict['title'] = "".join(title_elements)

                # 提取权重信息
                weight_keys = ["baidurank_br", "baidurank_mbr", "360_pr", "sm_pr", "sogou_pr", "google_pr"]
                for key in weight_keys:
                    alt_text = tree.xpath(f'//a[@id="{key}"]//img/@alt')[0]
                    result_dict['weights'][key] = alt_text

                # 提取备案信息
                icp_elements = tree.xpath('//ul[@id="icp"]//text()')
                result_dict['icp'] = " ".join(icp_elements).strip()

                return result_dict
            else:
                return {"url": url, "error": f"请求失败，状态码：{response.status_code}"}
        except Exception as e:
            return {"url": url, "error": str(e)}

    def run(self):
        for idx, url in enumerate(self.urls):
            result = self.query_aizhan(url.strip())
            self.result.emit(result)
        self.finished.emit()

def format_url(url):
    """仅保留URL的hostname部分，移除协议、路径、查询参数等。"""
    parsed_url = urlparse(url)
    # 如果URL没有scheme（协议），且netloc（网络位置，即域名+端口）为空，
    # 表明输入可能就是纯净的域名，直接返回原输入。
    if not parsed_url.scheme and not parsed_url.netloc:
        return url.strip()  # 去除可能的前后空白
    # 否则，返回hostname部分
    return parsed_url.hostname

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setFixedSize(1200, 600)  # 固定窗口大小，不允许用户调整
        self.threadpool = None  # 初始化线程池变量
        self.initUI()
        self.all_results = []

    def center_on_screen(self):
        # 获取屏幕的几何信息
        screen_geometry = QDesktopWidget().availableGeometry()
        # 计算窗口应处于的中心位置
        window_size = self.geometry()
        center_point = screen_geometry.center() - window_size.center()
        # 移动窗口到计算出的中心位置
        self.move(center_point)

    def initUI(self):
        self.setWindowTitle('SEO权重查询工具 作者:挖洞两年半 1.0版')
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        self.setWindowIcon(QIcon('1.ico'))
        layout = QVBoxLayout()

        input_layout = QHBoxLayout()
        self.url_input = QLineEdit()
        self.url_input.setPlaceholderText("请输入需要查询的url")
        self.query_button = QPushButton('查询单个URL')
        self.query_button.clicked.connect(self.query_single_url)
        self.batch_button = QPushButton('批量查询（TXT）')
        self.batch_button.clicked.connect(self.query_batch_url)
        input_layout.addWidget(self.url_input)
        input_layout.addWidget(self.query_button)
        input_layout.addWidget(self.batch_button)
        layout.addLayout(input_layout)

        self.result_text = QTextEdit()
        self.result_text.setReadOnly(True)
        layout.addWidget(self.result_text)

        central_widget.setLayout(layout)

    @pyqtSlot()
    def query_single_url(self):
        raw_url = self.url_input.text().strip()
        formatted_url = format_url(raw_url)  # 新增：格式化URL
        if not formatted_url:
            self.result_text.append("请输入有效的URL进行查询。")
            return

        if self.threadpool and self.threadpool.isRunning():
            self.threadpool.quit()
            self.threadpool.wait()

        self.result_text.clear()
        self.threadpool = QThread()
        self.worker = BatchQueryWorker([formatted_url])  # 使用格式化后的URL
        self.worker.moveToThread(self.threadpool)

        self.worker.result.connect(self.display_result)
        self.worker.finished.connect(self.on_query_finished)
        self.worker.error.connect(self.display_error)

        self.threadpool.started.connect(self.worker.run)
        self.threadpool.start()

    @pyqtSlot()
    def query_batch_url(self):
        file_dialog = QFileDialog()
        file_path, _ = file_dialog.getOpenFileName(self, '选择TXT文件', '', 'TXT Files (*.txt)')
        if file_path:
            try:
                with open(file_path, 'r', encoding='utf-8') as file:
                    raw_urls = file.read().splitlines()
                    formatted_urls = [format_url(url) for url in raw_urls]  # 新增：格式化所有URL
                    formatted_urls = [url for url in formatted_urls if url]  # 筛选出有效URL

                    if self.threadpool and self.threadpool.isRunning():
                        self.threadpool.quit()
                        self.threadpool.wait()

                    self.result_text.clear()
                    self.threadpool = QThread()
                    self.worker = BatchQueryWorker(formatted_urls)  # 使用格式化后的URL列表
                    self.worker.moveToThread(self.threadpool)

                    self.worker.result.connect(self.display_result)
                    self.worker.finished.connect(self.on_query_finished)
                    self.worker.error.connect(self.display_error)

                    self.threadpool.started.connect(self.worker.run)
                    self.threadpool.start()
            except Exception as e:
                self.result_text.append(f"读取文件时发生错误：{str(e)}")

    @pyqtSlot(dict)
    def display_result(self, result):
        """显示查询结果，权重信息键名转换为中文，备案信息显示在同一行"""
        url = result.get('url')
        if 'error' in result:
            self.result_text.append(f"查询URL {url} 时发生错误: {result['error']}")
        else:
            title_info = result.get('title', "标题信息无法获取")
            # 创建英文到中文的权重映射
            weight_mapping = {
                "baidurank_br": "百度权重",
                "baidurank_mbr": "移动百度权重",
                "360_pr": "360权重",
                "sm_pr": "搜狗权重",
                "sogou_pr": "搜狗网页评级",
                "google_pr": "谷歌PR值"
            }
            # 使用映射转换权重信息的键为中文，并构造输出字符串，同时确保备案信息在同一行显示
            weight_info_items = [(weight_mapping.get(k, k), v) for k, v in result['weights'].items()]
            weight_info = "    ".join([f"{k}: {v}" for k, v in weight_info_items])
            icp_info = result.get('icp', "备案信息无法获取").replace('\n', '').replace('\t', '').replace('：', ':').strip()  # 移除备案信息中的换行符并去除首尾空白

            self.result_text.append(f"\nURL: {url}\n标题: {title_info}\n权重信息: {weight_info}\n备案信息: {icp_info}")
            self.all_results.append(result)

    @pyqtSlot(tuple)
    def display_error(self, error_data):
        """处理查询中的错误"""
        idx, error_msg = error_data
        self.result_text.append(f"查询第 {idx + 1} 个URL时发生错误：{error_msg}")

    @pyqtSlot()
    def on_query_finished(self):
        """处理查询完成的信号"""
        self.result_text.moveCursor(QTextCursor.End)
        self.result_text.append("---------------------------------------------所有查询完成---------------------------------------------\n")
        # 保存结果到Excel文件
        self.save_results_to_excel()
        self.threadpool.quit()
        self.threadpool.wait()
        self.threadpool.deleteLater()
        self.worker.deleteLater()
        self.threadpool = None  # 清理线程池引用
        self.all_results = []  # 结果处理完毕后清空列表



    def save_results_to_excel(self):
        # 创建一个新的Excel工作簿
        wb = openpyxl.Workbook()
        ws = wb.active

        # 设置列标题
        ws.append(['URL', '百度权重', '备案信息'])

        # 将查询结果添加到工作表中
        for result in self.all_results:
            ws.append([
                result.get('url', ''),
                result.get('weights', {}).get('baidurank_br', ''),
                result.get('icp', "备案信息无法获取").replace('\n', '').replace('\t', '').replace('：', ':').strip()
            ])

        # 设置列的样式
        for col in ws.iter_cols(min_row=1, max_row=1, min_col=1, max_col=3):
            for cell in col:
                cell.font = Font(bold=True)
                cell.alignment = Alignment(horizontal='center', vertical='center')

        # 保存工作簿
        file_path = '查询结果.xlsx'
        wb.save(file_path)
        self.result_text.append(f"查询结果已保存至: {file_path}")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())
